package com.zzw.springboot.aspect;

import com.zzw.springboot.annotation.Log;
import com.zzw.springboot.bean.SysLog;
import com.zzw.springboot.service.SysLogService;
import com.zzw.springboot.util.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 日志切面类
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired(required = false)
    private SysLogService sysLogService;

    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.zzw.springboot.annotation.Log)")
    public void logPointcut() {
    }

    /**
     * 环绕通知
     */
    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 执行方法
        Object result = null;
        try {
            result = joinPoint.proceed();
            // 记录请求耗时
            long costTime = System.currentTimeMillis() - startTime;

            // 记录日志
            recordLog(joinPoint, result, costTime);

            return result;
        } catch (Throwable e) {
            log.error("方法执行异常", e);
            throw e;
        }
    }

    /**
     * 记录操作日志
     */
    private void recordLog(JoinPoint joinPoint, Object result, long costTime) {
        try {
            // 获取请求相关信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                log.warn("无法获取请求上下文，跳过日志记录");
                return;
            }
            HttpServletRequest request = attributes.getRequest();

            // 获取方法信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            // 获取注解信息
            Log logAnnotation = method.getAnnotation(Log.class);
            if (logAnnotation == null) {
                log.warn("未找到Log注解，跳过日志记录");
                return;
            }

            String module = logAnnotation.module();
            String type = logAnnotation.type();
            String description = logAnnotation.description();
            boolean logParams = logAnnotation.logParams();
            boolean logResult = logAnnotation.logResult();

            // 打印日志信息
            log.info("=== 操作日志 ===");
            log.info("模块: {}", module);
            log.info("操作类型: {}", type);
            log.info("描述: {}", description);
            log.info("请求方法: {}", request.getMethod());
            log.info("请求路径: {}", request.getRequestURI());
            log.info("IP地址: {}", IPUtils.getIpAddr(request));
            log.info("执行时间: {}ms", costTime);

            // 记录参数
            String params = "";
            if (logParams) {
                params = getRequestParams(joinPoint);
                log.info("请求参数: {}", params);
            }

            // 记录返回结果
            String resultStr = "";
            if (logResult && result != null) {
                // 简单处理，避免日志过长
                resultStr = result.toString();
                if (resultStr.length() > 500) {
                    resultStr = resultStr.substring(0, 497) + "...";
                }
                log.info("返回结果: {}", resultStr);
            }

            // 保存日志到数据库
            if (sysLogService != null) {
                try {
                    SysLog sysLog = new SysLog();
                    sysLog.setModule(module);
                    sysLog.setType(type);
                    sysLog.setDescription(description);
                    sysLog.setMethod(request.getMethod());
                    //sysLog.setRequestUri(request.getRequestURI());
                    sysLog.setIp(IPUtils.getIpAddr(request));
                    sysLog.setCostTime(costTime);
                    sysLog.setParams(params);
                    sysLog.setResult(resultStr);
                    sysLog.setCreateTime(new Date());
                    sysLogService.save(sysLog);
                } catch (Exception e) {
                    log.error("保存日志到数据库失败", e);
                }
            }

        } catch (Exception e) {
            log.error("记录操作日志失败", e);
        }
    }

    /**
     * 获取请求参数字符串
     */
    private String getRequestParams(JoinPoint joinPoint) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            String[] parameterNames = signature.getParameterNames();
            Object[] args = joinPoint.getArgs();

            StringBuilder sb = new StringBuilder();
            if (parameterNames != null && parameterNames.length > 0) {
                for (int i = 0; i < parameterNames.length; i++) {
                    if (args[i] == null) {
                        sb.append(parameterNames[i]).append("=null, ");
                        continue;
                    }

                    // 避免记录密码等敏感信息
                    if (parameterNames[i].toLowerCase().contains("password") ||
                        parameterNames[i].toLowerCase().contains("pwd")) {
                        sb.append(parameterNames[i]).append("=********, ");
                        continue;
                    }

                    String value = args[i].toString();
                    // 简单处理，避免日志过长
                    if (value.length() > 100) {
                        value = value.substring(0, 97) + "...";
                    }
                    sb.append(parameterNames[i]).append("=").append(value).append(", ");
                }
                if (sb.length() > 0) {
                    sb.delete(sb.length() - 2, sb.length());
                }
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("获取请求参数失败", e);
            return "获取参数异常: " + e.getMessage();
        }
    }
}
